/**
 * ## 生成菜单列表
 * 根据给定的数据和父路径，构建一个包含路径和子菜单的路由列表
 * @param {Array} data - 菋单数据数组，每个元素包含菜单的属性，如名称、路径和子菜单
 * @param {String} [parentPath='/'] - 父路径，用于构建当前菜单的完整路径，顶级菜单默认为null
 * @param {Array} [parentTitles=[]] - 父标题数组，用于构建当前菜单的完整标题
 * @returns {Array} - 返回一个路由列表，包含每个菜单的完整路径和子菜单（如果存在）
 */
export function getMenuList(data, parentPath = '/', parentTitles = []) {
    // 减少重复计算，循环外缓存结果，判断当前路径是否包含'/full'，以决定菜单项名称前是否加上 full- 前缀
    const isFull = parentPath?.indexOf('/full') !== -1;
    return data.map(item => {
        // 验证菜单项结构的完整性
        if (!item || !item.path || !item.meta || !item.meta.title) {
            throw new Error('Invalid menu item structure');
        }
        // 对菜单项路径进行清理和验证
        const sanitizedPath = sanitizePath(item.path);
        // 构建当前菜单项的完整路径
        const path = parentPath !== '/' ? `${parentPath}/${sanitizedPath}` : `/${sanitizedPath}`;
        // 根据是否是完整路径，决定菜单项名称的形式
        const name = isFull ? `full-${item.name}` : item.name;
        // 构建当前菜单项的完整标题数组
        const titles = parentTitles.length ? [...parentTitles, item.meta.title] : [item.meta.title];
        // 构建并返回当前菜单项对象
        const menuItem = {
            ...item,
            meta: {
                ...item.meta,
                titles,
            },
            name,
            path,
        };

        // 如果当前菜单项包含子菜单，则递归调用getMenuList处理子菜单
        if ('children' in item) {
            menuItem.children = getMenuList(item.children, path, titles);
        }

        return menuItem;
    });
}

/**
 * 清理和验证路径，防止恶意路径导致的路径注入攻击，并返回一个安全的路径。
 * @param {String} path - 待验证的路径
 * @returns {String} - 返回验证后的安全路径
 */
function sanitizePath(path) {
    // 简单的路径验证，可以根据实际需求进一步增强
    return path.replace(/(\.\.\/|\/\.\.|[^\w-\/]+)/g, '');
}

/**
 * ## 合并菜单列表
 * 该函数接收一个菜单数据数组，递归处理每个菜单项，如果菜单项包含子菜单，则递归处理子菜单，
 * 最终返回一个合并后的菜单列表，其中所有子菜单都被展开。
 * @param {Array} data - 菜单数据数组，每个菜单项可能包含一个children属性，表示子菜单。
 * @returns {Array} 返回处理后的菜单数据数组，所有子菜单都被展开。
 */
export function getFlatMenuList(data) {
    let menuList = flatMenuList(data)
    return menuList.flat(Infinity)
}

/**
 * ## 将多层级菜单数据转换为单层级菜单数据的函数。
 * 主要用于处理树形结构数据，将多级嵌套的菜单扁平化为一维数组。
 * @param {Array} data - 多级菜单的数据数组，每个菜单项可能包含children属性表示子菜单。
 * @returns {Array} - 返回扁平化后的菜单数据数组，不包含任何子菜单项。
 */
function flatMenuList(data) {
    // 使用map函数遍历菜单数据数组
    return data.map(item => {
        // 判断当前菜单项是否包含子菜单
        if ('children' in item) {
            // 如果包含子菜单，则递归调用concatMenuList处理子菜单
            return flatMenuList(item.children)
        }
        // 如果不包含子菜单，则直接返回当前菜单项
        return item
    })
}

/**
 * ## 检查给定的路由是否存在于当前的路由配置中。
 * 该函数通过比较路由的路径和名称来确定路由是否存在。
 * 它主要用于路由管理中，确保要操作的路由是已定义的。
 * @param {Array} currentRoutes 当前的路由配置数组，每个路由包含路径和名称。
 * @param {Object} routeToCheck 需要检查的路由对象，包含路径和名称。
 * @returns {boolean} 如果路由存在返回true，否则返回false。
 */
export function routeExists(currentRoutes, routeToCheck) {
    return currentRoutes.some(route =>
        route.path === routeToCheck.path &&
        route.name === routeToCheck.name
    );
}